#ifndef _NET_PACKET_H
#define _NET_PACKET_H

#include "defines.h"
#include "netselect.h"

template< xgc_size capacity >
class CNetPacket
{
public:
	CNetPacket( CNetSelect& net )
		: mNet( net )
		, mBase( mBuffer )
		, mCurrent( mBuffer )
	{
	}

	~CNetPacket()
	{
	}

private:
	void move_to_head()
	{
		memcpy( mBuffer, mBase, mCurrent - mBase );
		mCurrent = mBuffer + ( mCurrent - mBase );
		mBase = mBuffer;
	}

public:
	xgc_lpcstr Done()throw( std::logic_error )
	{
		xgc_int32 nRead = mNet.Recv( (xgc_lpstr)mCurrent, mBuffer + capacity - mCurrent );
		
		if( nRead < 0 )
		{
			throw std::logic_error( "network error." );
		}

		mCurrent += nRead;

		// header recv complated.
		if( mCurrent - mBase >= 4 )
		{
			xgc_uint16 length = *(xgc_uint16*)mBase;

			if( length > capacity )
			{
				throw std::logic_error( "packet length too long." );
			}

			// release not enough, then move buffer to begin pos
			if( length > mBuffer + capacity - mBase )
			{
				move_to_head();
			}

			if( mCurrent - mBase >= length )
				return (xgc_lpcstr)mBase;
		}
		return xgc_nullptr;
	}

	void Next()
	{
		xgc_uint16 length = *(xgc_uint16*)mBase;
		mBase += length;

		if( mBase > mBuffer + capacity/2 )
		{
			move_to_head();
		}
	}

	template< xgc_size length, typename message >
	xgc_int32 Send( const message& msg )throw( std::logic_error )
	{
		xgc_byte buffer[length];

		bufstream s( buffer+sizeof(xgc_uint16), length-sizeof(xgc_uint16) );
		s << msg;

		*(xgc_uint16*)(buffer) = s.wd()+sizeof(xgc_uint16);
		return mNet.Send( (xgc_lpstr)buffer, s.wd()+sizeof(xgc_uint16) );
	}
private:
	CNetSelect& mNet;
	xgc_byte mBuffer[capacity];

	xgc_byte *mBase;
	xgc_byte *mCurrent;
};
#endif
